<template>
  <a-modal
    title="分配权限"
    :visible="visible"
    @ok="handleRole"
    @cancel="emit('update:visible', false)"
    width="600px"
  >
    <a-space style="margin-bottom: 10px">
      <a-checkbox v-model="expandAll">展开/折叠</a-checkbox>
      <a-checkbox v-model="selectAll">全选/全不选</a-checkbox>
      <a-checkbox v-model="cascade">父子节点关联</a-checkbox>
    </a-space>

    <a-tree
      v-model:checked-keys="selectedKeys"
      :data="treeData"
      :expanded-keys="expandedKeys"
      v-model:selected-keys="selectedKeys"
      :check-strictly="!cascade"
      :checkable="true"
      :multiple="true"
      @expand="handleExpand"
      @check="handleCheck"
    />
  </a-modal>
</template>

<script setup lang="ts">
  import { defineProps, defineEmits, ref, watch, onMounted, h } from 'vue';
  import { authRole } from '@/api/syssetting';
  import { getMenuList } from '@/api/menu';
  import SvgIcon from '@/components/svgIcon/index.vue';
  import { Message } from '@arco-design/web-vue';
  import { deepClone } from '@arco-vue-pro-components/pro-components/es/pro-table/utils';

  const treeData = ref();
  const props = defineProps<{
    visible: Boolean;
    params: object;
  }>();
  const emit = defineEmits(['update:visible', 'refresh']);

  // 展开/折叠
  const expandAll = ref(true);
  const expandedKeys = ref<string[]>([]);
  const getAllKeys = (data: any[]): string[] => {
    return data.flatMap((node) => [
      node.key,
      ...(node.children ? getAllKeys(node.children) : []),
    ]);
  };

  watch(expandAll, (val) => {
    expandedKeys.value = val ? getAllKeys(deepClone(treeData.value)) : [];
  });

  // 全选/全不选
  const selectAll = ref(false);
  const selectedKeys = ref<string[]>([]);
  const getAllNodeKeys = (data: any[]): string[] => {
    return data.flatMap((node) => [
      node.key,
      ...(node.children ? getAllNodeKeys(node.children) : []),
    ]);
  };

  watch(selectAll, (val) => {
    if (val) {
      selectedKeys.value = getAllNodeKeys(treeData.value);
    } else {
      selectedKeys.value = [];
    }
  });

  watch(selectedKeys, (newVal) => {
    const allKeys = getAllNodeKeys(treeData.value);
    selectAll.value = newVal.length === allKeys.length;
  });

  // 父子关联
  const cascade = ref(false);
  const menusIds = ref();
  watch(
    () => props.params,
    (newVal) => {
      menusIds.value = newVal.menuIds;
    },
    {
      immediate: true,
      deep: true,
    }
  );

  // 处理节点展开或收缩事件
  const handleExpand = (expandedKeysArr: string[]) => {
    expandedKeys.value = expandedKeysArr;
  };

  // 处理复选框选中事件
  const handleCheck = (checkedKeys: string[], { checkedNodes }) => {
    let newCheckedKeys = [...checkedKeys];
    if (cascade.value) {
      // 找出新增选中的节点
      const addedKeys = checkedNodes
        .filter((node) => checkedKeys.includes(node.key))
        .map((node) => node.key);

      // 遍历新增选中的节点，添加其父节点
      addedKeys.forEach((key) => {
        newCheckedKeys = newCheckedKeys.concat(
          findParentKeys(key, treeData.value)
        );
      });
      // 去重
      newCheckedKeys = Array.from(new Set(newCheckedKeys));
    }
    selectedKeys.value = newCheckedKeys;
  };

  // 递归查找父节点的 key
  const findParentKeys = (key: string, nodes: any[]): string[] => {
    let parentKeys: string[] = [];
    for (const node of nodes) {
      if (node.children) {
        const childKeys = node.children.map((child: any) => child.key);
        if (childKeys.includes(key)) {
          parentKeys.push(node.key);
          parentKeys = parentKeys.concat(findParentKeys(node.key, nodes));
        } else {
          const childParentKeys = findParentKeys(key, node.children);
          if (childParentKeys.length > 0) {
            parentKeys.push(node.key);
            parentKeys = parentKeys.concat(childParentKeys);
          }
        }
      }
    }
    return parentKeys;
  };

  // 在组件挂载时设置初始展开状态和选中状态
  onMounted(() => {
    getMenuList({}).then((res: any) => {
      treeData.value = transformDeptTree(
        res.data.list,
        'menu_id',
        'menu_id',
        'menu_name'
      );
      if (expandAll.value) {
        expandedKeys.value = getAllKeys(treeData.value);
      }
      // 根据 menusIds 设置初始选中状态
      if (menusIds.value) {
        selectedKeys.value = getKeysFromMenuIds(menusIds.value);
      }
    });
  });

  function transformDeptTree(
    depts: any,
    parentKey: string,
    idName = 'id',
    name?: any
  ) {
    return depts.map((dept: any, index: any) => {
      return {
        title: dept[name],
        key: dept[parentKey],
        id: dept[idName],
        icon: () =>
          h(SvgIcon, {
            class: 'icon',
            style: {
              width: '1.2em',
              height: '1.2em',
            },
            name: 'icon-agreement',
          }),
        children: transformDeptTree(
          dept.children || [],
          parentKey,
          idName,
          name
        ),
      };
    });
  }

  // 根据 menuIds 获取对应的 keys
  function getKeysFromMenuIds(menuIds: number[]): string[] {
    const keys: string[] = [];
    function traverseNodes(nodes: any[]) {
      nodes.forEach((node) => {
        if (menuIds.includes(node.id)) {
          keys.push(node.key);
        }
        if (node.children) {
          traverseNodes(node.children);
        }
      });
    }
    if (treeData.value) {
      traverseNodes(treeData.value);
    }
    return keys;
  }

  function handleRole() {
    if (selectedKeys.value.length === 0) {
      Message.error('请选择权限后确认！');
    } else {
      const menuIds = getMenuIdsFromKeys(selectedKeys.value);
      authRole({
        role_id: props.params.id,
        menu_ids: menuIds,
      }).then((res) => {
        if (res?.code === 200) {
          Message.success(res?.msg);
          emit('update:visible', false);
          emit('refresh');
        }
      });
    }
  }

  // 根据 keys 获取对应的 menuIds
  function getMenuIdsFromKeys(keys: string[]): number[] {
    const menuIds: number[] = [];
    function traverseNodes(nodes: any[]) {
      nodes.forEach((node) => {
        if (keys.includes(node.key)) {
          menuIds.push(node.id);
        }
        if (node.children) {
          traverseNodes(node.children);
        }
      });
    }
    if (treeData.value) {
      traverseNodes(treeData.value);
    }
    return menuIds;
  }
</script>

<style scoped lang="less"></style>
